package com.polaris.live.widget.gift

import android.content.Context
import android.util.AttributeSet
import android.view.Gravity
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.RelativeLayout
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.blankj.utilcode.util.ScreenUtils
import com.blankj.utilcode.util.StringUtils
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.constant.LiveConst
import com.polaris.live.databinding.WidgetGiftPagBinding
import com.polaris.live.im.sfs.bean.live.payload.InviteGiftPayloadBean
import com.polaris.live.manager.DownFileManager
import com.polaris.live.resp.bean.LiveShowPagBean
import com.polaris.live.translation.R.string
import com.polaris.live.utils.AudioPlayProxy
import com.polaris.live.utils.file.FileUtils
import com.polaris.live.utils.file.FileUtils.getFilePath
import com.polaris.live.utils.image.ImageUtils
import com.polaris.live.widget.pag.PagWidgetView
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.libpag.PAGFile
import org.libpag.PAGImage
import java.io.File
import java.util.concurrent.ConcurrentLinkedQueue

/**
 * LiveGiftPagView
 *
 * @author Created by 半仙 on 2023/11/27/027 16:33
 */
class LiveGiftPagView(context: Context, attrs: AttributeSet? = null) : FrameLayout(context, attrs) {

    private val mBinding = WidgetGiftPagBinding.inflate(LayoutInflater.from(context), this, true)

    private val mLifecycleOwner: LifecycleOwner by lazy {
        context as? LifecycleOwner
            ?: throw IllegalArgumentException("View context must implement LifecycleOwner")
    }

    private val mWaitingList = ConcurrentLinkedQueue<LiveShowPagBean>()

    private var mGiftPag: PagWidgetView? = null

    private var mContentJob: Job? = null

    //是否展示礼物特效
    private var mIsOpenGiftAnimation = true

    //是否播放礼物音效
    private var mIsOpenSound = true

    init {
        mLifecycleOwner.lifecycle.addObserver(object : LifecycleEventObserver {
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    mPagJob?.cancel()
                    mPagJob = null
                    mContentJob?.cancel()
                    mContentJob = null
                    AudioPlayProxy.instance().recycle()
                }
            }
        })
    }

    //添加礼物
    fun setGift(payload: InviteGiftPayloadBean) {
        if (mLifecycleOwner.lifecycle.currentState == Lifecycle.State.DESTROYED) {
            return
        }
        payload.gift.animation?.let {
            val liveShowPagBean =
                LiveShowPagBean(
                    0,
                    it,
                    payload.gift.heightWidthRatio ?: 1.0,
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    Gravity.BOTTOM, payload.layers,
                    payload.gift.soundEffect
                )
            var count = payload.giftCount
            if (payload.gift.type == LiveConst.GiftType.LUCK_GIFT) {
                count = 1
            }
            setLiveShowPagBean(count, liveShowPagBean)
        }
    }

    /**
     * 添加进场座驾
     */
    private fun setLiveShowPagBean(count: Int, liveShowPagBean: LiveShowPagBean) {
        if (mLifecycleOwner.lifecycle.currentState == Lifecycle.State.DESTROYED) {
            return
        }
        if (mGiftPag?.isPlaying == true || !mWaitingList.isEmpty()) {
            addQueue(1, liveShowPagBean)
        } else {
            if (count > 1) {
                addQueue(count - 1, liveShowPagBean)
            }
            showPag(liveShowPagBean)

        }
    }

    //加入等待队列
    private fun addQueue(count: Int, payload: LiveShowPagBean) {
        for (i in 0 until count) {
            mWaitingList.add(payload)
        }
    }

    //展示礼物
    private fun showPag(liveShowPagBean: LiveShowPagBean) {
        val path = getFilePath(FileUtils.getPagFile(), liveShowPagBean.pagUrl)
        //如果文件里没有找到 就代表没有下载过 那么就去下载 然后播放下一个
        if (!File(path).exists()) {
            showNext()
            downLoadPag(liveShowPagBean)
            return
        }
        liveShowPagBean.soundEffect?.let {
            val soundEffectFile = getFilePath(FileUtils.getAudioFile(), it)
            if (!File(soundEffectFile).exists()) {
                showNext()
                downLoadPag(liveShowPagBean)
                return
            }
        }

        val width = ViewGroup.LayoutParams.MATCH_PARENT
        val height = (ScreenUtils.getScreenWidth() * liveShowPagBean.heightWidthRatio).toInt()
        mGiftPag = PagWidgetView(context)
        val layout = RelativeLayout.LayoutParams(width, height)
        when (liveShowPagBean.gravity) {
            Gravity.CENTER -> {
                layout.addRule(RelativeLayout.CENTER_HORIZONTAL)
                layout.addRule(RelativeLayout.CENTER_VERTICAL)
            }

            Gravity.BOTTOM -> {
                layout.addRule(RelativeLayout.CENTER_HORIZONTAL)
                layout.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
            }

            Gravity.TOP -> {
                layout.addRule(RelativeLayout.CENTER_HORIZONTAL)
                layout.addRule(RelativeLayout.ALIGN_PARENT_TOP)
            }

            else -> {
                layout.addRule(RelativeLayout.CENTER_HORIZONTAL)
                layout.addRule(RelativeLayout.CENTER_VERTICAL)
            }
        }
        mGiftPag?.layoutParams = layout
        mBinding.llPag.removeAllViews()
        mBinding.llPag.addView(mGiftPag)
        val pagFile = PAGFile.Load(path)
        val layers = liveShowPagBean.layers
        if (layers != null) {
            mContentJob = CoroutineScopeManager.ioScope.launch {
                val texts = layers.text
                if (texts?.isNotEmpty() == true) {
                    texts.forEach {
                        val showText = if (it.value.length > 8) {
                            it.value.substring(0, 8)
                        } else {
                            it.value
                        }
                        val textData = pagFile.getTextData(it.index)
                        textData.text = showText
                        pagFile.replaceText(it.index, textData)
                    }
                }
                val images = layers.image
                if (images?.isNotEmpty() == true) {
                    images.forEach {
                        val loadNetImageBitmap = if (it.rounded == false) {
                            ImageUtils.loadNetImageBitmapNoTransform(context, it.value)
                        } else {
                            ImageUtils.loadNetImageBitmap(context, it.value)
                        }
                        val pagImage = PAGImage.FromBitmap(loadNetImageBitmap)
                        pagFile.replaceImage(it.index, pagImage)
                    }
                }

                withContext(CoroutineScopeManager.mainDispatcher) {
                    StartPag(pagFile, liveShowPagBean)
                }
            }
        } else {
            StartPag(pagFile, liveShowPagBean)
        }
    }

    private fun StartPag(pagFile: PAGFile, liveShowPagBean: LiveShowPagBean) {
        if (mIsOpenSound) {
            liveShowPagBean.soundEffect?.let {
                AudioPlayProxy.instance().init(it)
                AudioPlayProxy.instance().playSound()
            }
        }
        if (mIsOpenGiftAnimation) {
            mGiftPag?.apply {
                setRepeatCount(1)
                composition = pagFile
                setOnPagEndCallback {
                    AudioPlayProxy.instance().recycle()
                    showNext()
                }
                startPag()
            }
        }
    }

    //展示下一个
    private fun showNext() {
        mGiftPag = null
        mWaitingList.poll()?.let {
            showPag(it)
        }
    }

    fun clearAllPag() {
        clearQueue()
        mBinding.llPag.removeAllViews()
    }

    fun clearQueue() {
        mWaitingList.clear()
        mLoadQueue.clear()
    }

    private var mIsDownloading = false   //是否正在下载中
    private val mLoadQueue = ConcurrentLinkedQueue<LiveShowPagBean>() //下载队列
    private var mPagJob: Job? = null

    //下载
    private fun downLoadPag(liveShowPagBean: LiveShowPagBean) {
        if (mIsDownloading) {
            mLoadQueue.add(liveShowPagBean)
            return
        }
        val path = getFilePath(FileUtils.getPagFile(), liveShowPagBean.pagUrl)
        //如果pag没有下载则下载pag去
        if (!File(path).exists()) {
            downPag(true, liveShowPagBean.pagUrl) {
                checkSoundFile(liveShowPagBean)
            }
        } else {
            checkSoundFile(liveShowPagBean)
        }
    }

    private fun checkSoundFile(liveShowPagBean: LiveShowPagBean) {
        //pag下载完检查有没有音频文件
        val sound = liveShowPagBean.soundEffect
        if (sound != null) {//有音频就接着下
            val soundEffectFile = getFilePath(FileUtils.getAudioFile(), sound)
            if (!File(soundEffectFile).exists()) {
                downPag(false, liveShowPagBean.soundEffect) {
                    loadNextPag(liveShowPagBean)
                }
            } else {
                loadNextPag(liveShowPagBean)
            }
        } else {//没有音频就去放，然后下载下一个pag
            loadNextPag(liveShowPagBean)
        }
    }

    private fun loadNextPag(liveShowPagBean: LiveShowPagBean) {
        setLiveShowPagBean(1, liveShowPagBean)
        mLoadQueue.poll()?.let {
            downLoadPag(it)
        }
    }

    private fun downPag(isPage: Boolean, url: String, back: () -> Unit) {
        mPagJob?.cancel()
        mIsDownloading = true
        mPagJob = CoroutineScopeManager.ioScope.launch {
            try {
                val directory = if (isPage) FileUtils.getPagFile() else FileUtils.getAudioFile()
                val loadFileCallback = DownFileManager.loadFileCallback(directory, url)
                withContext(CoroutineScopeManager.mainDispatcher) {
                    mIsDownloading = false
                    loadFileCallback?.second?.let {
                        back.invoke()
                    }
                }
            } finally {
                if (coroutineContext[Job] == mPagJob) {
                    mPagJob = null
                }
            }
        }

    }

    //礼物动效开关  如果动效关了音效也要关
    fun setIsOpenGiftAnimation(isOpen: Boolean) {
        mIsOpenGiftAnimation = isOpen
        mIsOpenSound = isOpen
        clearQueue()
        AudioPlayProxy.instance().recycle()
        if (isOpen) {
            ToastGravity.showGravity(StringUtils.getString(string.gift_and_sound_is_open))
        } else {
            ToastGravity.showGravity(StringUtils.getString(string.gift_and_sound_is_closure))
        }
    }

    //礼物音效开关
    fun setIsOpenSound(isOpen: Boolean) {
        if (isOpen) {
            if (mIsOpenGiftAnimation) {
                ToastGravity.showGravity(StringUtils.getString(string.sound_is_open))
            } else {
                ToastGravity.showGravity(StringUtils.getString(string.please_open_gift_animation))
                return
            }
        } else {
            ToastGravity.showGravity(StringUtils.getString(string.sound_is_closure))
        }
        mIsOpenSound = isOpen
    }

    fun getIsOpenGift() = mIsOpenGiftAnimation

    fun getIsOpenSound() = mIsOpenSound
}